// 我门在学习ts的过程中主要学习的是ts如何写类型 （ts关注的是类型，类型是核心，不是业务逻辑）
// 类型的分类： 基础类型、高级类型、内置类型(D0M、Promise 原始方法，它们自带的提示)、自定义类型、类型体操
// TS的类型都是在变量后面来写 ：后面是类型 ，= 后面是值 (ts语法，不是js对象)
// ts的特点，如何来学习？

// 1).ts的目的是什么？从安全角度来考虑使用 (考虑我在赋予结果的时候 是否会发生错误)  error lens
// 2).ts是用来检测类型的，只是提示作用，不是在运行的时候发生的 (运行的时候和ts无关，“代码没有被执行”)
// 3).编译ts之后 类型就消失了，不存在类型了（写的都是空气） 最终生生产环境下 可以增添.d.ts 来对js文件增加类型声明

// ts的特点：在编写代码的时候 并不是所有的变量都要添加类型。
// （ts中支持类型推导，根据赋的值来猜测他的类型） 如果猜测的类型是对的不用给类型, 如果猜测的不对，或者类型无法正确的推导 自己写类型

// 1） string number boolean   小写 ===> 是用来描述基础类型
const name: string = "jw";
const age: number = 30;
const gender: boolean = true;

/* 
// 大写类型都是装箱类型(包装类),用来描述对象 高级类型
class Dog {}
let dog: Dog = new Dog(); 
*/

// 关于大小写错误问题
/* let s1: string = "jiangwen"; // 正确
let s2: string = new String("jiangwen"); // 错误 string 小写 ===> 是用来描述基础类型,不能声明对象 
let s3: String = new String("jiangwen"); // 正确
let s4: String = "jiangwen"; // 正确 */

// 基础类型， 包装类型
// 规范 小写的类型一般用于描述基本类型 大写的用来描述的是实例类型
let s1: string = "abc";
// let s2:string = new String('abc')
let s3: String = "1"; // 在赋予值的时候 子集可以赋予给父级
let s4: String = new String("1"); // 类的类型，类类型，用来描述实例的

// 我们在使用基本类型的时候 需要采用的时候 小写类型来标识

// 数组的概念：用于存储多个类型相同的集合.......................................................................
// 数组   声明 ====>类型[]  Array<类型> 都可以用于声明数组
let arr1: number[] = [1, 2, 3, 4, 5];
let arr2: string[] = ["1", "2", "3", "4", "5"];
// 泛型
let arr3: Array<number | string> = [1, 2, 3, 4, 5, "6"];
// (number | string) ===>联合类型
let arr4: (number | string)[] = [1, 2, 3, "a", "b", "c"];

//，不关心位置
// ts特性 元组 ====> 规定数组长度 和 每个成员的类型
// 你赋予的值要求得符合这个结构和顺序, 元组在新增内容的时候 不能增加额外的类型的值，只能是已有的类型，而且增加后无法访问，访问会报错
// let tuple = ["1", 1, "1", 1]; ==> 相当于 let tuple: (number | string)[]  = ["1", 1, "1", 1];
let tuple: [string, number, string, number] = ["1", 1, "1", 1];

// 已经约定好没有第四个，后续增加的不算，访问的时候不能访问后增加，安全问题
let item: string = tuple[2];

// 枚举： 自带类型的对象（自己有类型，就是一个对象）.......................................................................
// 约定一组格式我们会用枚举  状态码 权限 数据格式 标志位

// 自带类型的对象;自动增长，会被编译成个对象
// 数字类型的枚举可以反举，值是数字的时候 可以反过来枚举）, 枚举没有值会根据上面的索引来自动累加
// 1)自动增长
// var STATUS1 = { 0: USER, 1: ADMIN, 2: MANAGER, USER: 0, 1: ADMIN: 1, MANAGER: 2 }
// const r = STATUS1[1];  0: USER, 1: ADMIN, 2: MANAGER, 反举
// const r = STATUS1["USER"]; USER: 0, 1: ADMIN: 1, MANAGER: 2 正举
enum STATUS1 { // 数字类型的枚举
  USER,
  ADMIN,
  MANAGER,
}

enum STATUS2 { // 异构枚举 就是枚举中不光有数字 还有字符串. 异构枚举上一个是字符串下一个无法推导
  USER,
  ADMIN = 6,
  MANAGER, // 自动推断上一个的值类型，数字自动增长 MANAGER 值为 7
  OTHER = "abc",
  // 自动推断上一个的值类型，数字自动增长由于OTHER = "abc" OTHER1无法自动推断，会报错，需要主动赋值
  //   OTHER1 = 0, 反举 STATUS2[0] 返回值是OTHER1，不是USER，会出现覆盖情况
  //   OTHER1,
}

// 2)编译 维护一组常量的时候 可以采用枚举
const enum STATUS3 { // 常量枚举 不会额外编译成对象， 所以更节约
  "OK" = "ok",
  "NO_OK" = 100,
  "NOT_FOUND",
}
// 3)访问 const r = STATUS3[0]; // 因为不会额外编译成对象， const r = STATUS3[0] 会报错
const r = STATUS3["OK"];
console.log(r);

// null  undefined  ，.。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
// 严格检测 ，正常情况下只能赋予给null 和 undefined
// 非严格模式在关闭的时候 null可以赋予给undefiend

const u: undefined = undefined;
const n: null = null;
// 如果禁用非严格null检测，null和undefiend 可以赋予给任何类型 （null,undefiend任何类型的子类型）

// void 类型代表的是空类型  void  这个void一般值表示函数的返回值，只在函数中使用.................................
// unefiend 可以赋予给void， 都代表空 (undefiend 是 void的子类型)
function a(): void {
  return undefined;
}

// never 永远不，永远达到不了的地方就是never.......................................
// 情况一
// 函数无法执行完毕
function whileTrue(): never {
  while (true) { } // 函数无法达到执行完毕的状态
}
// 情况二
function throwError(): never {
  throw Error(); // 出错函数无法执行完毕
}
// 情况三 类型保护 完整性保护==> 保护代码的完整性
// 如果if/else 条件都走完了， 没有遗漏的 后面的类型就是never (完整性保护)
function validateCheck(v: never) { }
function toArray(val: number | string | boolean) {
  // typeof 可以有收窄功能
  if (typeof val === "number") {
    // number处理
    return val.toString().split("").map(Number); // [1,1,1]
  }
  if (typeof val === "string") {
    // string处理
    return val.split(""); // [1,1,1]
  }
  if (typeof val === "boolean") {
    // boolean处理
    return val.toString().split(""); // [1,1,1]
  }
  // never类型 只能被never类型来赋予值
  // 上述只要val类型判断漏了一个，validateCheck(val)这里就会报错
  validateCheck(val); // 代码的完整性保护
}
toArray("abc");

let union: string | number | boolean | never; // never 参与联合，是被忽略的 never 和其他类型做联合类型最终是不显示的

// any 任何类型 能不写any 就不要用any ，
// any会导致类型丧失检测
// anyScript(如果我们的项目是采用ts编写的，一般情况下any的出现场景不多) 放弃检测，出错就怨自己。 没有ts的加持

// let a1:any = 1;  ====> a1可以赋值任何类型
// let a2;// 声明一个变量不给类型默认就是any类型，即使赋值了a2还是any

// object 对象类型
// {} object Object的区别
// {}，0bject 不采用，偶尔会使用{}表示对象上无任何属性。 都可以将任何值赋予给{}或者 0bject
// object 非基础类型
const create = (target: object) => { };
create(function () { });
create({});
create([]);

//Symbol BigInt es6 新增的
let d1: symbol = Symbol.for("1");
let d2: symbol = Symbol.for("1");
console.log(d1 === d2); // 返回true
// let d1: symbol = Symbol("1");
// let d2: symbol = Symbol("1");
// console.log(d1 === d2)// 返回false

const bigint: bigint = BigInt(Number.MAX_SAFE_INTEGER + 1);

// string number boolean 数组  元组 枚举  null undefiend void never any objectr symbol bigInt

export { }; // 这是一个独立的模块，不好影响其他人
